﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace PrototypeZGame
{
    public class PlayerController : Controller
    {
        public enum State
        {
            Normal,
            TakeItem,
            DropItem,
            Dead,
        }

        public State state;
        protected KeyboardState oldKeyboardState, newKeyboardState;
        protected MouseState oldMouseState, newMouseState;
        protected Camera2D camera;
        public bool finished;



        public PlayerController(World world, Camera2D camera): base(world)
        {
            this.camera = camera;
            finished = false;
        }
    
        public void Update(KeyboardState keyboardState, MouseState mouseState)
        {
            bool numericPressed = true;
            newKeyboardState = keyboardState;
            newMouseState = mouseState;

            if (isKeyPressed(Keys.P) || isKeyPressed(Keys.Pause)) world.pause = true;
            if (isKeyPressed(Keys.L)) world.pause = false;

            if (isKeyPressed(Keys.Y)) world.clear = true;

            if (unit == null)
            {
                finished = true;
                return;
            }

            if (unit.AP <= 0.0f)
            {
                finished = true;
                return;
            }

            switch (state)
            {
                case State.Normal:
                    if (oldKeyboardState != newKeyboardState) target = null;
                    if (target != null) ProceedToTarget();
                    
                    if (isKeyPressed(Keys.W)) walk(Direction.North);
                    else if (isKeyPressed(Keys.S)) walk(Direction.South);
                    else if (isKeyPressed(Keys.A)) walk(Direction.West);
                    else if (isKeyPressed(Keys.D)) walk(Direction.East);

                    if (isKeyPressed(Keys.P)) world.debugPathfinding = !world.debugPathfinding;
                    if (isKeyPressed(Keys.R)) unit.running = !unit.running; // Toggle running
                    if (isKeyPressed(Keys.Space)) finished = true;  // End turn

                    if (isKeyPressed(Keys.D1)) unit.useItem(0);
                    else if (isKeyPressed(Keys.D2)) unit.useItem(1);
                    else if (isKeyPressed(Keys.D3)) unit.useItem(2);
                    else if (isKeyPressed(Keys.D4)) unit.useItem(3);
                    else if (isKeyPressed(Keys.D5)) unit.useItem(4);
                    else if (isKeyPressed(Keys.D6)) unit.useItem(5);
                    else if (isKeyPressed(Keys.D7)) unit.useItem(6);
                    else if (isKeyPressed(Keys.D8)) unit.useItem(7);
                    else if (isKeyPressed(Keys.D9)) unit.useItem(8);
                    else if (isKeyPressed(Keys.D0)) unit.useItem(9);

                    if (isKeyPressed(Keys.T)) state = State.TakeItem;
                    else if (isKeyPressed(Keys.G)) state = State.DropItem;

                    if (oldMouseState.LeftButton == ButtonState.Released && newMouseState.LeftButton == ButtonState.Pressed) onClick();
                    if (oldMouseState.RightButton == ButtonState.Released && newMouseState.RightButton == ButtonState.Pressed) onRightClick();

                    break;

                case State.TakeItem:
                    
                    if (isKeyPressed(Keys.D1)) unit.takeItem(0);
                    else if (isKeyPressed(Keys.D2)) unit.takeItem(1);
                    else if (isKeyPressed(Keys.D3)) unit.takeItem(2);
                    else if (isKeyPressed(Keys.D4)) unit.takeItem(3);
                    else if (isKeyPressed(Keys.D5)) unit.takeItem(4);
                    else if (isKeyPressed(Keys.D6)) unit.takeItem(5);
                    else if (isKeyPressed(Keys.D7)) unit.takeItem(6);
                    else if (isKeyPressed(Keys.D8)) unit.takeItem(7);
                    else if (isKeyPressed(Keys.D9)) unit.takeItem(8);
                    else if (isKeyPressed(Keys.D0)) unit.takeItem(9);
                    else numericPressed = false;

                    if (numericPressed || isKeyPressed(Keys.T) || isKeyPressed(Keys.Space)) state = State.Normal;
                    break;

                case State.DropItem:

                    if (isKeyPressed(Keys.D1)) unit.dropItem(0);
                    else if (isKeyPressed(Keys.D2)) unit.dropItem(1);
                    else if (isKeyPressed(Keys.D3)) unit.dropItem(2);
                    else if (isKeyPressed(Keys.D4)) unit.dropItem(3);
                    else if (isKeyPressed(Keys.D5)) unit.dropItem(4);
                    else if (isKeyPressed(Keys.D6)) unit.dropItem(5);
                    else if (isKeyPressed(Keys.D7)) unit.dropItem(6);
                    else if (isKeyPressed(Keys.D8)) unit.dropItem(7);
                    else if (isKeyPressed(Keys.D9)) unit.dropItem(8);
                    else if (isKeyPressed(Keys.D0)) unit.dropItem(9);
                    else numericPressed = false;

                    if (numericPressed || isKeyPressed(Keys.G) || isKeyPressed(Keys.Space)) state = State.Normal;
                    break;
            }

            oldKeyboardState = newKeyboardState;
            oldMouseState = newMouseState;

        }

        private void ProceedToTarget()
        {
            int[,] map;
            Vec2 S = unit.position;
            Vec2 A = new Vec2(S.x - world.DSR, S.y - world.DSR);
            Vec2 B = new Vec2(S.x + world.DSR + 1, S.y + world.DSR + 1);
            Vec2 D = target.position;

            world.pathFindingResult = map = Dijskra.getFieldsWeights(world.terrain, S, A, B, D);

            List<Direction> path = Dijskra.getPath(map, S - A, D - A);

            if (path != null)
            {
                if (walk(path[0]) != Result.NoBlock)
                {
                    target = null;
                }
            }
            else
            {
                target = null;
            }
        }

        protected override Result walk(Direction direction)
        {
            Result ret = unit.walk(direction);
            camera.centerOn(unit);
            return ret;
        }

        private bool isKeyPressed(Keys key) 
        {
            return oldKeyboardState.IsKeyUp(key) && newKeyboardState.IsKeyDown(key);
        }


        private bool isKeyReleased(Keys key)
        {
            return oldKeyboardState.IsKeyDown(key) && newKeyboardState.IsKeyUp(key);
        }

        private void onClick()
        {
            Field field = world.terrain.worldPositionToField(world.mouseWorldPosition);
            if (field != null)
            {

                foreach (Zombie z in field.onFieldZombies)
                {
                    if (!z.dead && z.handsReach >= World.Distance(z, unit))
                    {
                        unit.Attack(z);
                        return;
                    }
                }

                foreach (Item item in field.onFieldItems)
                {
                    Door door = item as Door;
                    if (door != null)
                    {
                        if (unit.handsReach >= World.Distance(door, unit))
                        {
                            unit.toggle(door);
                            return;
                        }
                    }
                }
            }
        }

        

        public override void newTurn()
        {
            base.newTurn();
            finished = false;
        }

        private void onRightClick()
        {
            Field field = world.terrain.worldPositionToField(world.mouseWorldPosition);
            if (field != null)
            {
                target = field;
            }
        }

        public override void UnitDied()
        {
            state = State.Dead;
        }
    }
}
